package com.iplant.wms.serviceImpl.dao.wms;

import com.iplant.base.po.BasePO;
import com.iplant.base.po.BaseUser;
import com.iplant.base.po.OutResult;
import com.iplant.base.po.enums.ExceptionTypes;
import com.iplant.base.utils.annotation.dao.DBBaseDAO;
import com.iplant.base.utils.cache.CacheUtils;
import com.iplant.base.utils.general.StringUtils;
import com.iplant.base.utils.sql.BaseDAO;
import com.iplant.basic.service.po.bms.BMSEmployee;
import com.iplant.wms.service.basicenum.wms.WMSStockRecordType;
import com.iplant.wms.service.po.mfs.WMSStoreStation;
import com.iplant.wms.service.po.wms.WMSStockOperateRecord;
import com.iplant.wms.service.po.wms.WMSStockRecord;
import lombok.extern.slf4j.Slf4j;

import java.util.*;

@Slf4j
@DBBaseDAO(WMSStockOperateRecord.class)
public class WMSStockRecordOperateDAO extends BaseDAO {

    private static WMSStockRecordOperateDAO Instance = null;

    private WMSStockRecordOperateDAO() {
        super("");
        this.Init();
    }

    public static WMSStockRecordOperateDAO getInstance() {
        if (Instance == null) {
            synchronized (WMSStockRecordOperateDAO.class) {
                if (Instance == null) {
                    Instance = new WMSStockRecordOperateDAO();
                }
            }
        }
        return Instance;
    }


    /**
     * 库存迁移
     *
     * @param wLoginUser
     * @param wWMSStockRecord
     * @param wRecordType
     * @param wErrorCode
     * @return
     */
    public List<WMSStockOperateRecord> WMS_ChangeStockRecord(
            BMSEmployee wLoginUser, WMSStockRecord wWMSStockRecord, int wRecordType, int wStationID, int wTargetRecordType, float wMaterialNum, double wTotalVolume,
            double wTotalGrossWeight, double wTotalNetWeight, double wTotalPrice, String wRemark,
            OutResult<Integer> wErrorCode) {
        List<WMSStockOperateRecord> wResult = new ArrayList<>();
        wErrorCode.set(0);

        try {

            if (wWMSStockRecord == null || wWMSStockRecord.ID <= 0 || wRecordType <= 0 || wStationID <= 0 || wTargetRecordType <= 0 || wMaterialNum <= 0) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }

            wWMSStockRecord = WMSStockRecordDAO.getInstance().SelectPO(wLoginUser, wWMSStockRecord.ID,
                    "", wErrorCode);

            if (wErrorCode.Result != 0)
                return wResult;

            if (wWMSStockRecord == null || wWMSStockRecord.ID <= 0) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }

            WMSStockRecordType wStockRecordType = WMSStockRecordType.getEnumType(wRecordType);
            if (wStockRecordType == WMSStockRecordType.Default) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }
            WMSStockRecordType wTargetStockRecordType = WMSStockRecordType.getEnumType(wTargetRecordType);
            if (wTargetStockRecordType == WMSStockRecordType.Default) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }

            WMSStoreStation wWMSStoreStation = CacheUtils.GetCacheInfo(WMSStoreStation.class, wStationID, "");

            if (wWMSStoreStation == null || wWMSStoreStation.ID <= 0) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }

            switch (wStockRecordType) {

                case GeneralWarehousing:
                case ProductionWarehousing:
                case ProductionReturnWarehousing:
                case ProcurementAndWarehousing:
                case StockShiftIn:
                case UnBlockedStock:
                case InventoryProfit:

                    switch (wTargetStockRecordType) {
                        case GeneralOutOfStock:
                        case ProductionOutOfStock:
                        case ProductionFeedOutOfStock:
                        case SalesOutOfStock:
                        case StockShiftOut:
                        case BlockedStock:
                        case InventoryLoss:
                            break;
                        case Default:
                        case GeneralWarehousing:
                        case ProductionWarehousing:
                        case ProductionReturnWarehousing:
                        case ProcurementAndWarehousing:
                        case StockShiftIn:
                        case UnBlockedStock:
                        case InventoryProfit:
                        default:
                            wErrorCode.set(ExceptionTypes.Parameter.getValue());
                            break;
                    }

                    break;
                case GeneralOutOfStock:
                case ProductionOutOfStock:
                case ProductionFeedOutOfStock:
                case SalesOutOfStock:
                case StockShiftOut:
                case BlockedStock:
                case InventoryLoss:
                case Default:
                default:
                    wErrorCode.set(ExceptionTypes.Parameter.getValue());
                    break;
            }

            if (wErrorCode.Result != 0)
                return wResult;
            WMSStockOperateRecord wWMSStockOperateRecord = new WMSStockOperateRecord();
            wWMSStockOperateRecord.setStockRecord(wWMSStockRecord);
            wWMSStockOperateRecord.MaterialNum = wMaterialNum;
            wWMSStockOperateRecord.TotalVolume = wTotalVolume;
            wWMSStockOperateRecord.TotalGrossWeight = wTotalGrossWeight;
            wWMSStockOperateRecord.TotalNetWeight = wTotalNetWeight;
            wWMSStockOperateRecord.TotalPrice = wTotalPrice;
            wWMSStockOperateRecord.Description = wRemark;
            wWMSStockOperateRecord.RecordType = wStockRecordType.getValue();

            wResult.add(wWMSStockOperateRecord);

            this.WMS_UpdateStockRecordOperate(wLoginUser, wWMSStockOperateRecord, wErrorCode);

            if (wErrorCode.Result != 0)
                return wResult;

            wWMSStockOperateRecord = new WMSStockOperateRecord();
            wWMSStockOperateRecord.setStockRecord(wWMSStockRecord);
            wWMSStockOperateRecord.RecordID = 0;
            wWMSStockOperateRecord.setStoreStation(wWMSStoreStation);
            wWMSStockOperateRecord.MaterialNum = wMaterialNum;
            wWMSStockOperateRecord.TotalVolume = wTotalVolume;
            wWMSStockOperateRecord.TotalGrossWeight = wTotalGrossWeight;
            wWMSStockOperateRecord.TotalNetWeight = wTotalNetWeight;
            wWMSStockOperateRecord.TotalPrice = wTotalPrice;
            wWMSStockOperateRecord.Description = wRemark;
            wWMSStockOperateRecord.RecordType = wTargetStockRecordType.getValue();

            wResult.add(wWMSStockOperateRecord);

            this.WMS_UpdateStockRecordOperate(wLoginUser, wWMSStockOperateRecord, wErrorCode);


        } catch (Exception ex) {
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            log.error("WMS_ChangeStockRecord", ex);
        }
        return wResult;
    }


    /**
     * 库存操作
     *
     * @param wLoginUser
     * @param wWMSStockRecord
     * @param wRecordType
     * @param wErrorCode
     * @return
     */
    public int WMS_ChangeStockRecord(
            BMSEmployee wLoginUser, WMSStockRecord wWMSStockRecord, int wRecordType, float wMaterialNum, double wTotalVolume,
            double wTotalGrossWeight, double wTotalNetWeight, double wTotalPrice, String wRemark,
            OutResult<Integer> wErrorCode) {
        int wResult = 0;
        wErrorCode.set(0);

        try {

            if (wWMSStockRecord == null || wWMSStockRecord.ID <= 0 || wRecordType <= 0 || wMaterialNum <= 0) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }

            wWMSStockRecord = WMSStockRecordDAO.getInstance().SelectPO(wLoginUser, wWMSStockRecord.ID,
                    "", wErrorCode);

            if (wErrorCode.Result != 0)
                return wResult;

            if (wWMSStockRecord == null || wWMSStockRecord.ID <= 0) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }

            WMSStockRecordType wStockRecordType = WMSStockRecordType.getEnumType(wRecordType);

            if (wStockRecordType == WMSStockRecordType.Default) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }

            WMSStockOperateRecord wWMSStockOperateRecord = new WMSStockOperateRecord();
            wWMSStockOperateRecord.setStockRecord(wWMSStockRecord);
            wWMSStockOperateRecord.MaterialNum = wMaterialNum;
            wWMSStockOperateRecord.TotalVolume = wTotalVolume;
            wWMSStockOperateRecord.TotalGrossWeight = wTotalGrossWeight;
            wWMSStockOperateRecord.TotalNetWeight = wTotalNetWeight;
            wWMSStockOperateRecord.TotalPrice = wTotalPrice;
            wWMSStockOperateRecord.Description = wRemark;
            wWMSStockOperateRecord.RecordType = wStockRecordType.getValue();

            this.WMS_UpdateStockRecordOperate(wLoginUser, wWMSStockOperateRecord, wErrorCode);

        } catch (Exception ex) {
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            log.error("WMS_ChangeStockRecord", ex);
        }
        return wResult;
    }



    @Override
    public <T extends BasePO> void UpdatePoList(BaseUser wLoginUser, List<T> wBasePOList,boolean wIsAlone, boolean wIsChecked, OutResult<Integer> wErrorCode) {
        if ((wLoginUser instanceof BMSEmployee) && wBasePOList.size() > 0 && (wBasePOList.get(0) instanceof WMSStockOperateRecord)) {

            for (T wBasePO : wBasePOList) {
                this.WMS_UpdateStockRecordOperate((BMSEmployee) wLoginUser, (WMSStockOperateRecord) wBasePO, wErrorCode);
                if (wErrorCode.Result != 0)
                    break;
            }

        } else {
            super.UpdatePoList(wLoginUser, wBasePOList, wErrorCode);
        }
    }


    @Override
    public <T extends BasePO> int UpdatePo(BaseUser wLoginUser, T wBasePO, boolean wIsChecked, OutResult<Integer> wErrorCode) {
        if ((wLoginUser instanceof BMSEmployee) && (wBasePO instanceof WMSStockOperateRecord))
            return this.WMS_UpdateStockRecordOperate((BMSEmployee) wLoginUser, (WMSStockOperateRecord) wBasePO, wErrorCode);

        return super.UpdatePo(wLoginUser, wBasePO, wIsChecked, wErrorCode);
    }


    public int WMS_UpdateStockRecordOperate(BMSEmployee wLoginUser, WMSStockOperateRecord wWMSStockOperateRecord, OutResult<Integer> wErrorCode) {
        int wResult = 0;
        wErrorCode.set(0);

        try {

            if (wWMSStockOperateRecord == null || wWMSStockOperateRecord.StoreStationID <= 0
                    || wWMSStockOperateRecord.BatchRecordID <= 0 || wWMSStockOperateRecord.MaterialID <= 0 || wWMSStockOperateRecord.UnitID <= 0
                    || wWMSStockOperateRecord.CustomerID <= 0 || wWMSStockOperateRecord.RecordType <= 0
                    || wWMSStockOperateRecord.MaterialNum <= 0) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }

            WMSStoreStation wWMSStoreStation = CacheUtils.GetCacheInfo(WMSStoreStation.class,
                    wWMSStockOperateRecord.StoreStationID, "");

            if (wWMSStoreStation == null || wWMSStoreStation.ID <= 0) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }
            wWMSStockOperateRecord.setStoreStation(wWMSStoreStation);

            WMSStockRecordType wStockRecordType = WMSStockRecordType.getEnumType(wWMSStockOperateRecord.RecordType);

            WMSStockRecord wWMSStockRecord = WMSStockRecordDAO.getInstance().WMS_QueryStockRecord(wLoginUser,
                    wWMSStockOperateRecord.StoreStationID, wWMSStockOperateRecord.MaterialID, wWMSStockOperateRecord.BatchRecordID, "", wErrorCode);
            if (wErrorCode.Result != 0)
                return wResult;

            if (wWMSStockRecord == null || wWMSStockRecord.ID <= 0) {
                switch (wStockRecordType) {

                    case GeneralWarehousing:
                    case ProductionWarehousing:
                    case ProductionReturnWarehousing:
                    case ProcurementAndWarehousing:
                    case StockShiftIn:
                        wWMSStockRecord = new WMSStockRecord(wWMSStockOperateRecord);
                        wWMSStockRecord.setUserInfo(wLoginUser);
                        WMSStockRecordDAO.getInstance().UpdatePo(wLoginUser, wWMSStockRecord, wErrorCode);

                        break;
                    default:
                        break;
                }
                if (wErrorCode.Result != 0)
                    return wResult;
                if (wWMSStockRecord == null || wWMSStockRecord.ID <= 0) {
                    wErrorCode.Result = ExceptionTypes.Logic.getValue();
                    return wResult;
                }

                wWMSStockRecord = WMSStockRecordDAO.getInstance().WMS_QueryStockRecord(wLoginUser,
                        wWMSStockOperateRecord.StoreStationID, wWMSStockOperateRecord.MaterialID,
                        wWMSStockOperateRecord.BatchRecordID, "", wErrorCode);
                if (wErrorCode.Result != 0)
                    return wResult;
            }
            wWMSStockOperateRecord.setStockRecord(wWMSStockRecord);

            wWMSStockOperateRecord.setUserInfo(wLoginUser);

            //查询记录
            if (wWMSStockOperateRecord.ID > 0 || StringUtils.isNotEmpty(wWMSStockOperateRecord.Code)) {
                WMSStockOperateRecord wStockOperateRecord = this.SelectPO(wLoginUser, wWMSStockOperateRecord.ID, wWMSStockOperateRecord.Code, wErrorCode);
                if (wStockOperateRecord != null && wStockOperateRecord.ID > 0) {
                    //存在即修改记录，修改意味需要回退数量 回退体积这些
                    switch (wStockRecordType) {
                        case GeneralWarehousing:
                        case ProductionWarehousing:
                        case ProductionReturnWarehousing:
                        case ProcurementAndWarehousing:
                        case InventoryProfit:
                        case StockShiftIn:
                            wWMSStockRecord.MaterialMarginNum -= wStockOperateRecord.MaterialNum;
                            wWMSStockRecord.TotalVolume -= wStockOperateRecord.TotalVolume;
                            wWMSStockRecord.TotalGrossWeight -= wStockOperateRecord.TotalGrossWeight;
                            wWMSStockRecord.TotalNetWeight -= wStockOperateRecord.TotalNetWeight;
                            wWMSStockRecord.TotalPrice -= wStockOperateRecord.TotalPrice;
                            break;
                        case GeneralOutOfStock:
                        case ProductionOutOfStock:
                        case ProductionFeedOutOfStock:
                        case SalesOutOfStock:
                        case InventoryLoss:
                        case StockShiftOut:
                            wWMSStockRecord.MaterialMarginNum += wStockOperateRecord.MaterialNum;
                            wWMSStockRecord.TotalVolume += wStockOperateRecord.TotalVolume;
                            wWMSStockRecord.TotalGrossWeight += wStockOperateRecord.TotalGrossWeight;
                            wWMSStockRecord.TotalNetWeight += wStockOperateRecord.TotalNetWeight;
                            wWMSStockRecord.TotalPrice += wStockOperateRecord.TotalPrice;
                            break;
                        case UnBlockedStock:
                            //解冻回退数量
                            wWMSStockRecord.MaterialFreezeNum += wStockOperateRecord.MaterialNum;
                            break;
                        case BlockedStock:
                            //冻结回退数量
                            wWMSStockRecord.MaterialFreezeNum -= wStockOperateRecord.MaterialNum;
                            break;
                        case Default:
                        default:
                            break;
                    }
                }
            }

            //没有记录 判断是扣减还是删除
            switch (wStockRecordType) {
                case GeneralWarehousing:
                case ProductionWarehousing:
                case ProductionReturnWarehousing:
                case ProcurementAndWarehousing:
                case InventoryProfit:
                case StockShiftIn:
                    wWMSStockRecord.MaterialMarginNum += wWMSStockOperateRecord.MaterialNum;
                    wWMSStockRecord.TotalVolume += wWMSStockOperateRecord.TotalVolume;
                    wWMSStockRecord.TotalGrossWeight += wWMSStockOperateRecord.TotalGrossWeight;
                    wWMSStockRecord.TotalNetWeight += wWMSStockOperateRecord.TotalNetWeight;
                    wWMSStockRecord.TotalPrice += wWMSStockOperateRecord.TotalPrice;
                    break;
                case GeneralOutOfStock:
                case ProductionOutOfStock:
                case ProductionFeedOutOfStock:
                case SalesOutOfStock:
                case InventoryLoss:
                case StockShiftOut:
                    wWMSStockRecord.MaterialMarginNum -= wWMSStockOperateRecord.MaterialNum;
                    wWMSStockRecord.TotalVolume -= wWMSStockOperateRecord.TotalVolume;
                    wWMSStockRecord.TotalGrossWeight -= wWMSStockOperateRecord.TotalGrossWeight;
                    wWMSStockRecord.TotalNetWeight -= wWMSStockOperateRecord.TotalNetWeight;
                    wWMSStockRecord.TotalPrice -= wWMSStockOperateRecord.TotalPrice;
                    if (wWMSStockRecord.MaterialMarginNum <= 0) {
                        wWMSStockRecord.TotalVolume = 0;
                        wWMSStockRecord.TotalGrossWeight = 0;
                        wWMSStockRecord.TotalNetWeight = 0;
                        wWMSStockRecord.TotalPrice = 0;
                    }
                    break;
                case UnBlockedStock:
                    //解冻数量
                    wWMSStockRecord.MaterialFreezeNum -= wWMSStockOperateRecord.MaterialNum;
                    break;
                case BlockedStock:
                    //冻结数量
                    wWMSStockRecord.MaterialFreezeNum += wWMSStockOperateRecord.MaterialNum;
                    break;
                case Default:
                default:
                    break;
            }
            WMSStockRecordDAO.getInstance().UpdatePo(wLoginUser, wWMSStockRecord, wErrorCode);
            if (wErrorCode.Result != 0)
                return wResult;
            wWMSStockOperateRecord.MaterialMarginNum = wWMSStockRecord.MaterialMarginNum;

            wResult = super.UpdatePo(wLoginUser, wWMSStockOperateRecord, false, wErrorCode);


        } catch (Exception ex) {
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            log.error("WMS_UpdateStockRecordOperate", ex);
        }
        return wResult;
    }


    public void WMS_DeleteStockRecordOperate(BMSEmployee wLoginUser, int wID, OutResult<Integer> wErrorCode) {

        wErrorCode.set(0);

        try {

            if (wID <= 0) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return;
            }

            WMSStockOperateRecord wStockOperateRecord = this.SelectPO(wLoginUser, wID, "", wErrorCode);

            if (wErrorCode.Result != 0 || wStockOperateRecord == null || wStockOperateRecord.ID <= 0)
                return;


            if (wStockOperateRecord.StoreStationID <= 0
                    || wStockOperateRecord.BatchRecordID <= 0 || wStockOperateRecord.MaterialID <= 0 || wStockOperateRecord.UnitID <= 0
                    || wStockOperateRecord.CustomerID <= 0 || wStockOperateRecord.RecordType <= 0
                    || wStockOperateRecord.MaterialNum <= 0) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return;
            }


            WMSStockRecordType wStockRecordType = WMSStockRecordType.getEnumType(wStockOperateRecord.RecordType);

            WMSStockRecord wWMSStockRecord = WMSStockRecordDAO.getInstance().WMS_QueryStockRecord(wLoginUser,
                    wStockOperateRecord.StoreStationID, wStockOperateRecord.MaterialID, wStockOperateRecord.BatchRecordID, "", wErrorCode);
            if (wErrorCode.Result != 0)
                return;

            if (wWMSStockRecord != null && wWMSStockRecord.ID > 0) {
                //存在即修改记录，修改意味需要回退数量 回退体积这些
                switch (wStockRecordType) {
                    case GeneralWarehousing:
                    case ProductionWarehousing:
                    case ProductionReturnWarehousing:
                    case ProcurementAndWarehousing:
                    case InventoryProfit:
                    case StockShiftIn:
                        wWMSStockRecord.MaterialMarginNum -= wStockOperateRecord.MaterialNum;
                        wWMSStockRecord.TotalVolume -= wStockOperateRecord.TotalVolume;
                        wWMSStockRecord.TotalGrossWeight -= wStockOperateRecord.TotalGrossWeight;
                        wWMSStockRecord.TotalNetWeight -= wStockOperateRecord.TotalNetWeight;
                        wWMSStockRecord.TotalPrice -= wStockOperateRecord.TotalPrice;
                        break;
                    case GeneralOutOfStock:
                    case ProductionOutOfStock:
                    case ProductionFeedOutOfStock:
                    case SalesOutOfStock:
                    case InventoryLoss:
                    case StockShiftOut:
                        wWMSStockRecord.MaterialMarginNum += wStockOperateRecord.MaterialNum;
                        wWMSStockRecord.TotalVolume += wStockOperateRecord.TotalVolume;
                        wWMSStockRecord.TotalGrossWeight += wStockOperateRecord.TotalGrossWeight;
                        wWMSStockRecord.TotalNetWeight += wStockOperateRecord.TotalNetWeight;
                        wWMSStockRecord.TotalPrice += wStockOperateRecord.TotalPrice;
                        break;
                    case UnBlockedStock:
                        //解冻回退数量
                        wWMSStockRecord.MaterialFreezeNum += wStockOperateRecord.MaterialNum;
                        break;
                    case BlockedStock:
                        //冻结回退数量
                        wWMSStockRecord.MaterialFreezeNum -= wStockOperateRecord.MaterialNum;
                        break;
                    case Default:
                    default:
                        break;
                }
                WMSStockRecordDAO.getInstance().UpdatePo(wLoginUser, wWMSStockRecord, wErrorCode);
                if (wErrorCode.Result != 0)
                    return;
            }

            this.DeletePO(wLoginUser, wStockOperateRecord, wErrorCode);

            if (wWMSStockRecord != null && wWMSStockRecord.ID > 0
                    && wWMSStockRecord.MaterialMarginNum == 0 && wWMSStockRecord.MaterialFreezeNum == 0)
                WMSStockRecordDAO.getInstance().WMS_DeleteStockRecord(wLoginUser, wWMSStockRecord, wErrorCode);


        } catch (Exception ex) {
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            log.error("WMS_UpdateStockRecordOperate", ex);
        }

    }


    public void WMS_DeleteStockRecordOperateList(BMSEmployee wLoginUser, List<Integer> wIDList, OutResult<Integer> wErrorCode) {

        if (wIDList == null || wIDList.size() == 0)
            return;

        for (Integer wID : wIDList) {
            if (wID <= 0)
                continue;
            this.WMS_DeleteStockRecordOperate(wLoginUser, wID, wErrorCode);
            if (wErrorCode.Result != 0)
                break;
        }
        //将数量减少为0
    }


}
